package zwz.importTask.strategy;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zwz.importTask.enums.ExcelImportExportSateEnum;
import zwz.importTask.enums.ImportAndExportTaskEnum;
import zwz.importTask.mapper.BiDataImportTaskMapper;
import zwz.importTask.pojo.BiDataImportTaskPO;
import zwz.importTask.utils.ProgressWriteHandler;
import zwz.importTask.utils.ImportContext;
import zwz.importTask.utils.ImportThreadLocalUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Slf4j
public abstract class AbstractExcelExportStrategy<T> {

    private final Logger logger = LoggerFactory.getLogger(AbstractExcelExportStrategy.class);
    @Resource
    private BiDataImportTaskMapper biDataImportTaskMapper;

    /**
     * 执行导出任务
     */
    public void doExport(Integer type, HttpServletResponse response, String params) throws IOException {
        ImportContext<T> exportContext = ImportThreadLocalUtils.getContext();
        List<T> exportedData = getExportedData(params);
        exportContext.setFileType(type);
        exportContext.setFileName(ImportAndExportTaskEnum.getMenuNameByType(type));
        exportContext.setTotalRecords(exportedData.size());
        initImportRecord();
        doExportData(exportedData, response);
    }

    /**
     * 获取需要导出的数据
     */
    protected abstract List<T> getExportedData(String params);

    /**
     * 导出数据，使用 EasyExcel 写入文件
     */
    private void doExportData(List<T> data, HttpServletResponse response) throws IOException {
        ImportContext<T> exportContext = ImportThreadLocalUtils.getContext();
        String fileName = exportContext.getFileName();

        // 创建一个 ByteArrayOutputStream 用来存储 Excel 数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

//        try (OutputStream outputStream = baos) {
//            // 使用 EasyExcel 导出
//            EasyExcel.write(outputStream, getExcelClass()).sheet("导出数据").doWrite(data);
//        } catch (IOException e) {
//            logger.error("Error writing Excel file to ByteArrayOutputStream", e);
//            throw e;
//        }

        try (OutputStream outputStream = baos) {
            // 使用 EasyExcel 导出
            EasyExcel.write(outputStream, getExcelClass())
                    .registerWriteHandler(new ProgressWriteHandler(biDataImportTaskMapper))
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .sheet("导出数据")
                    .doWrite(data);
        } catch (IOException e) {
            logger.error("Error writing Excel file to ByteArrayOutputStream", e);
            throw e;
        }

        // 设置文件名及响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));

        // 将 ByteArrayOutputStream 的内容写入 HttpServletResponse
        try (OutputStream responseOutputStream = response.getOutputStream()) {
            baos.writeTo(responseOutputStream);
            responseOutputStream.flush();
        } catch (IOException e) {
            logger.error("Error writing Excel file to HttpServletResponse", e);
            throw e;
        }

        // 上传到 OSS
//        uploadToOSS(baos.toByteArray(), fileName);
//        exportContext.setOriginFileUrl("www.baidu.com");
        // 最终进度更新
        finallyUpdateImportRecord();
    }

    /**
     * 获取 Excel 模型类
     */
    protected abstract Class<T> getExcelClass();


    private void initImportRecord() {
        ImportContext<T> exportContext = ImportThreadLocalUtils.getContext();
        BiDataImportTaskPO biDataImportTaskPO = new BiDataImportTaskPO();
        biDataImportTaskPO.setTaskNo(UUID.randomUUID().toString());
        biDataImportTaskPO.setImportDataType(exportContext.getFileType());
        biDataImportTaskPO.setMenuName(exportContext.getFileName());
        biDataImportTaskPO.setStatus(ExcelImportExportSateEnum.PROCESS.getKey());
        biDataImportTaskPO.setErrorFileUrl("");
        biDataImportTaskPO.setCreatedTime(new Date());
        biDataImportTaskPO.setModifiedTime(new Date());
        biDataImportTaskPO.setStartTime(new Date());
        biDataImportTaskPO.setFileName(exportContext.getFileName());
        biDataImportTaskPO.setTotalRecord(exportContext.getTotalRecords());
        biDataImportTaskMapper.insert(biDataImportTaskPO);
        exportContext.setBiDataImportTaskPO(biDataImportTaskPO);
    }

    private void finallyUpdateImportRecord() {
        BiDataImportTaskPO biDataImportTaskPO = ImportThreadLocalUtils.getContext().getBiDataImportTaskPO();
        biDataImportTaskPO.setStatus(ExcelImportExportSateEnum.SUCCESS.getKey());
        biDataImportTaskPO.setSucceedRecord(ImportThreadLocalUtils.getContext().getTotalRecords());
        biDataImportTaskPO.setTime((int) (System.currentTimeMillis() - biDataImportTaskPO.getStartTime().getTime()) / 1000);
        biDataImportTaskPO.setTotalRecord(ImportThreadLocalUtils.getContext().getTotalRecords());
        biDataImportTaskPO.setFailRecord(0);
        biDataImportTaskPO.setModifiedTime(new Date());
        biDataImportTaskPO.setEndTime(new Date());
        biDataImportTaskMapper.updateById(biDataImportTaskPO);
    }
}
